#include <iostream>
#include <sys/select.h>
#include <unistd.h>
#include <cstdlib>
#include <memory>
#include <sys/time.h>
#include "Socket.hpp"

#define MAX_FD_NUM sizeof(fd_set) * 8
#define DEFAULT_FD -1
int readfd_arrry[MAX_FD_NUM];

using namespace std;
class Select
{
public:
    Select(int _port = gdefault_port) : _is_running(false)
    {
        _socket_tcp = make_unique<Socket_tcp>(_port);
    }
    void Init()
    {
        _socket_tcp->Create();
        for (int i = 0; i < MAX_FD_NUM; i++)
        {
            readfd_arrry[i] = DEFAULT_FD;
        }
        readfd_arrry[0] = _socket_tcp->Socket_fd();
    }
    void Start()
    {
        _is_running = true;
        fd_set read_set;
        while (_is_running)
        {
            int maxfd = readfd_arrry[0];
            FD_ZERO(&read_set);
            for (int i = 0; i < MAX_FD_NUM; i++)
            {
                if (readfd_arrry[i] != -1)
                    FD_SET(readfd_arrry[i], &read_set);
            }
            for (int i = 1; i < MAX_FD_NUM; i++)
            {
                if (readfd_arrry[i] == -1)
                    continue;
                else if (readfd_arrry[i] > maxfd)
                    maxfd = readfd_arrry[i];
            }

            struct timeval timeout;
            timeout.tv_sec = 5;
            timeout.tv_usec = 0;
            int n = select(maxfd + 1, &read_set, nullptr, nullptr, &timeout);
            switch (n)
            {
            case -1:
                cout << "select error" << endl;
                break;
            case 0:
                cout << "timeout" << endl;
                break;
            default:
                cout << "已有IO就绪" << endl;
                Handrequest(read_set);
                break;
            }
        }
    }

    void Handrequest(fd_set &read_set)
    {
        for (int i = 0; i < MAX_FD_NUM; i++)
        {
            if (readfd_arrry[i] == DEFAULT_FD)
                continue;
            else if (readfd_arrry[i] == _socket_tcp->Socket_fd())
            {
                if (FD_ISSET(readfd_arrry[i], &read_set))
                {
                    cout << "连接新客户端中" << endl;
                    Getnewfd();
                }
            }
            else
            {
                if (FD_ISSET(readfd_arrry[i], &read_set))
                {
                    Echo(i);
                }
            }
        }
    }

    void Echo(int who)
    {
        char buf[1024];
        string getdata;
        int n = recv(readfd_arrry[who], buf, sizeof(buf) - 1, 0);
        buf[n] = '\0';
        if (n < 0)
        {
            perror("recv error");
            readfd_arrry[who] = DEFAULT_FD;
            close(readfd_arrry[who]);
        }
        else if (n == 0)
        {
            cout << "客户端断开连接" << endl;
            readfd_arrry[who] = DEFAULT_FD;
            close(readfd_arrry[who]);
        }
        else
        {
            getdata=buf;
            cout << "client#:" << buf << endl;
            getdata="#echo"+getdata;
            send(readfd_arrry[who], getdata.c_str(), getdata.length(), 0);
        }
        cout << endl;
    }

    void Getnewfd()
    {
        int newfd = _socket_tcp->Accept();
        if (newfd < 0)
        {
            perror("accept error");
        }
        else
        {
            int i = -1;
            for (int j = 0; j < MAX_FD_NUM; j++)
            {
                if (readfd_arrry[j] == DEFAULT_FD)
                {
                    i = j;
                    break;
                }
            }
            if (i == -1)
            {
                cout << "too many clients" << endl;
            }
            else
            {
                readfd_arrry[i] = newfd;
                cout << "客户端添加成功!" << endl;
            }
        }
        cout << endl;
    }

private:
    bool _is_running;
    unique_ptr<Socket> _socket_tcp;
};
